﻿using System;
using System.Collections.Generic;

using XNA = Microsoft.Xna.Framework;


namespace DKE_Kinect.Entwicklung.Grafik.ControlManaging
{
	/// <summary>
	/// Stellt ein Hauptmenü für das Projekt dar.
	/// </summary>
	public class PainectMenu : Control, IMenu<MenuItem>
	{
		#region Fields

		// Readonly - Fields
		private readonly int pCount = 8;

		private readonly int pOffsetButton = 5;
		private readonly int[] pOffsets = new int[] { 80, 171, 217, 240, 240, 217, 171, 80 };

		private readonly int pStandardWidth, pStandardHeight;

		// Controls
		private Control pBigButton;
		private Button[] pPrimLayer;
		private Button[] pSndLayer;

		private bool pShowNextLayer;

		// Saving Indexers & Sub Menus
		private int pCollapsedIndex;
		private int pSelectedIndex;
		private IMenu<MenuItem> pActiveMenu;
		private List<MenuItem> pSubItems;

		#endregion

		#region Constructor

		/// <summary>
		/// Instanziiert ein neues Objekt dieser Klasse.
		/// </summary>
		/// <param name="Owner">Gibt den übergeordneten Container an.</param>
		public PainectMenu (ContainerManager Owner)
			: base("Main Menu")
		{
			if (Owner == null)
				throw new NullReferenceException();


			base.Parent = Owner;

			this.pStandardWidth = this.pOffsetButton * 2 + this.pOffsets[3] + ContainerRessources.GetButtons(ButtonType.MainMenuHover)[3].Width * 2;
			this.pStandardHeight = ContainerRessources.GetButtons(ButtonType.BigButton)[0].Height;

			this.pBigButton = new Control("Big Button", ContainerRessources.GetButtons(ButtonType.BigButton)[0]);
			this.pBigButton.Visible = false;
			this.pBigButton.Layout = ControlManaging.Layout.Stretch;
			this.pBigButton.Size = new XNA.Point(this.pBigButton.Size.X - 10, this.pBigButton.Size.Y);
			this.pBigButton.Parent = this;

			this.pSubItems = new List<MenuItem>();

			this.pPrimLayer = new Button[this.pCount];
			this.pSndLayer = new Button[this.pCount];
			for (int i = 0; i < this.pCount; i++)
			{
				this.pPrimLayer[i] = new Button(string.Format("P{0}", i), i);
				this.pPrimLayer[i].Parent = this;
				this.pPrimLayer[i].Visible = false;
				this.pPrimLayer[i].Layout = ControlManaging.Layout.Stretch;
				this.pPrimLayer[i].Size = new XNA.Point(this.pPrimLayer[i].Size.X - 50, this.pPrimLayer[i].Size.Y);

				this.pSndLayer[i] = new Button(string.Format("S{0}", i), i);
				this.pSndLayer[i].Parent = this;
				this.pSndLayer[i].Visible = false;
				this.pSndLayer[i].Layout = ControlManaging.Layout.Stretch;
				this.pSndLayer[i].Size = new XNA.Point(this.pSndLayer[i].Size.X - 50, this.pSndLayer[i].Size.Y);
			}

			this.pCollapsedIndex = -1;
			this.pSelectedIndex = -1;
			this.pActiveMenu = this;

			this.pShowNextLayer = false;
			this.Size = Owner.Size;
			this.rearrangeItems();
		}

		#endregion

		#region Properties

		/// <summary>
		/// Gibt an, welche Art der Aktion hinter dem Menüpunkt steckt.
		/// </summary>
		public ActivationType ActivationType { get { return ActivationType.LayerForward; } }

		/// <summary>
		/// Gibt den Index dieses Menüpunktes gegenüber dem übergeordneten Menü an.
		/// </summary>
		public int Index { get { return -1; } }
		/// <summary>
		/// Gibt an, welcher Untermenüpunkt dieses Menüpunktes ausgewählt wurde oder legt diesen fest.
		/// </summary>
		public int SelectedIndex
		{
			get { return this.pSelectedIndex; }
			set
			{
				if ((value < -1) || (value >= this.pSubItems.Count))
					throw new IndexOutOfRangeException();

				if (value != this.pSelectedIndex)
					this.pSelectedIndex = value;
			}
		}
		/// <summary>
		/// Gibt an, welche Untermenüpunkt ausgeklappt wurde oder legt diesen fest.
		/// </summary>
		public int CollapsedIndex
		{
			get { return this.pCollapsedIndex; }
			set
			{
				if ((value < -1) || (value >= this.pSubItems.Count))
					throw new IndexOutOfRangeException();

				if (value != this.pCollapsedIndex)
					this.pCollapsedIndex = value;
			}
		}

		/// <summary>
		/// Gibt an, ob dieser Menüpunkt der Knoten / Wurzel des Menübaumes ist.
		/// </summary>
		public bool Root { get { return true; } }
		/// <summary>
		/// Gibt den übergeordneten Knoten dieses Menüpunktes an.
		/// </summary>
		public IMenu<MenuItem> PreviousLayer { get { return null; } }
		/// <summary>
		/// Gibt alle untergeordneten Menüpunkte an.
		/// </summary>
		public List<MenuItem> SubItems { get { return this.pSubItems; } }

		/// <summary>
		/// Gibt den ausgewählten Menüpunkt an.
		/// </summary>
		public MenuItem SelectedItem { get { return (this.pSelectedIndex < 0) ? null : this.pSubItems[this.pSelectedIndex]; } }

		/// <summary>
		/// Gibt den Text an, den dieser Menüpunkt darstellen soll.
		/// </summary>
		public new string Text { get { return string.Empty; } set { } }

		#endregion

		#region Methods

		//private void parentSizeChanged (object sender, EventArgs e)
		//{
		//  base.pSize = this.pParent.Size;
		//  this.rearrangeItems();
		//}

		/// <summary>
		/// Logo-Control und Menüpunkte neu anordnen.
		/// </summary>
		private void rearrangeItems ()
		{
			this.pBigButton.Location = new XNA.Point(this.pOffsetButton, (this.pSize.Y - this.pBigButton.Size.Y) / 2);
			int y = this.pBigButton.Location.Y;
			for (int i = 0; i < this.pPrimLayer.Length; i++)
			{
				this.pPrimLayer[i].Location = new XNA.Point(this.pOffsetButton + this.pOffsets[i] , y);
				this.pSndLayer[i].Location = new XNA.Point(this.pOffsetButton + this.pOffsets[i] + 390, this.pPrimLayer[i].Location.Y);

				y = this.pPrimLayer[i].Bounds.Bottom + 2;
			}
		}

		/// <summary>
		/// Setzt die Visible - Eigenschaft aller Buttons in der zweiten Ebene auf false.
		/// </summary>
		private void hideLayer ()
		{
			foreach (Button btn in this.pSndLayer)
				btn.Visible = false;
		}
		/// <summary>
		/// Setzt die Visible - Eigenschaft aller zu aktivierenden Buttons in der zweiten Ebene auf true.
		/// </summary>
		private void showLayer ()
		{
			for (int i = 0; i < this.pActiveMenu.SubItems.Count; i++)
			{
				this.pSndLayer[i].Text = this.pActiveMenu.SubItems[i].Text;
				this.pSndLayer[i].Visible = true;
			}

			if (this.pActiveMenu.SelectedIndex >= 0)
				this.pSndLayer[this.pActiveMenu.SelectedIndex].ActivateHoverEffect();

			this.pShowNextLayer = false;
		}

		/// <summary>
		/// Führt ein Update für diese und alle untergeordneten Komponenten aus.
		/// </summary>
		/// <param name="gameTime">Die Spielzeiteigenschaften.</param>
		public override void Update (XNA.GameTime gameTime)
		{
			if (this.pShowNextLayer)
			{
				bool layerVisible = false;
				foreach (Button btn in this.pSndLayer)
					layerVisible |= btn.Visible;

				if (!layerVisible)
					showLayer();
			}

			if (this.pRefreshRequested)
			{
				for (int i = 0; i < this.pSubItems.Count; i++)
					this.pPrimLayer[i].Text = this.pSubItems[i].Text;

				if (!this.pActiveMenu.Root)
					for (int i = 0; i < this.pActiveMenu.SubItems.Count; i++)
						this.pSndLayer[i].Text = this.pActiveMenu.SubItems[i].Text;
			}

			base.Update(gameTime);
		}

		/// <summary>
		/// Führt die jeweilige Aktion aus, die für den aktuell ausgewählten Menüunterpunkt vorgesehen ist (wie ein Klick, Tastendruck etc.)
		/// </summary>
		public void PerformAction ()
		{
			if (this.pActiveMenu.SelectedItem == null)
				return;

			switch (this.pActiveMenu.SelectedItem.ActivationType)
			{
				case ActivationType.LayerForward:
					this.hideLayer();
					this.pActiveMenu.CollapsedIndex = this.pActiveMenu.SelectedIndex;
					this.pActiveMenu = this.pActiveMenu.SelectedItem;
					this.pActiveMenu.SelectedIndex = 0;
					this.pActiveMenu.CollapsedIndex = -1;

					if (this.pActiveMenu.PreviousLayer.Root)
						this.showLayer();
					else
						this.pShowNextLayer = true;

					break;

				case ActivationType.LayerBackward:
					LayerBackward();

					break;

				case ActivationType.OwnDelegate:
					MenuItem subMenu = this.pActiveMenu.SelectedItem;

					if (subMenu != null)
						subMenu.Action();

					break;

				default:
					break;
			}
		}
		/// <summary>
		/// Springt zum Hauptmenü und versteckt den zweiten Layer.
		/// </summary>
		public void JumpFirst ()
		{
			this.hideLayer();
			this.pSndLayer[this.pActiveMenu.SelectedIndex].DeactivateHoverEffect();
			this.pActiveMenu.SelectedIndex = -1;
			this.pActiveMenu.CollapsedIndex = -1;
			this.pActiveMenu = this;
		}
		/// <summary>
		/// Geht eine Ebene zurück.
		/// </summary>
		public void LayerBackward ()
		{
			if (this.pActiveMenu.Root)
				return;

			this.hideLayer();
			this.pSndLayer[this.pActiveMenu.SelectedIndex].DeactivateHoverEffect();
			this.pActiveMenu.SelectedIndex = -1;
			this.pActiveMenu.CollapsedIndex = -1;
			this.pActiveMenu = this.pActiveMenu.PreviousLayer;

			if (!this.pActiveMenu.Root)
				this.pShowNextLayer = true;
		}
		/// <summary>
		/// Selektiert den Nachfolger im aktuellen Menülayer.
		/// </summary>
		public void Next ()
		{
			if (this.pActiveMenu.SubItems.Count < 1)
				return;

			Button[] activeLayer = (this.pActiveMenu.Root) ? this.pPrimLayer : this.pSndLayer;
			int buffer = this.pActiveMenu.SelectedIndex + 1;

			if (buffer < this.pActiveMenu.SubItems.Count)
			{
				if (this.pActiveMenu.SelectedIndex >= 0)
					activeLayer[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();
				this.pActiveMenu.SelectedIndex = buffer;
				activeLayer[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();
			}
		}
		/// <summary>
		/// Selektiert den Vorgänger im aktuellen Menülayer.
		/// </summary>
		public void Previous ()
		{
			if (this.pActiveMenu.SubItems.Count < 1)
				return;

			Button[] activeLayer = (this.pActiveMenu.Root) ? this.pPrimLayer : this.pSndLayer;
			int buffer = this.pActiveMenu.SelectedIndex - 1;

			if (buffer >= 0)
			{
				if (buffer < this.pActiveMenu.SubItems.Count)
					activeLayer[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();
				this.pActiveMenu.SelectedIndex = buffer;
				activeLayer[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();
			}
		}

		// Event Handling
		protected override void OnSizeChanged (EventArgs e)
		{
		//	this.resizeItems();
			base.OnSizeChanged(e);
		}

		/// <summary>
		/// Löst das Ergebnis VisisbleChanged aus.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnVisibleChanged (EventArgs e)
		{
			base.OnVisibleChanged(e);
			if (this.pVisible)
			{
				this.pActiveMenu = this;

				this.pBigButton.Visible = true;
				for (int i = 0; i < this.pSubItems.Count; i++)
				{
					this.pPrimLayer[i].Text = this.pSubItems[i].Text;
					this.pPrimLayer[i].Visible = true;
				}

				if (this.pActiveMenu.SubItems.Count > 0)
				{
					this.pActiveMenu.SelectedIndex = 0;
					this.pPrimLayer[this.pActiveMenu.SelectedIndex].ActivateHoverEffect();
				}
				else
					this.pActiveMenu.SelectedIndex = 0;
			}
			else
			{
				this.pBigButton.Visible = false;
				for (int i = 0; i < this.pCount; i++)
				{
					this.pPrimLayer[i].Visible = false;
					this.pSndLayer[i].Visible = false;
				}
			}
		}

		/// <summary>
		/// Selektiert diesen Menüpunkt.
		/// </summary>
		public void Select ()
		{
			throw new NotImplementedException();
		}
		/// <summary>
		/// Gibt den Wurzelknoten im Menübaum an.
		/// </summary>
		/// <returns></returns>
		public IMenu<MenuItem> GetRoot ()
		{
			return this;
		}

		#endregion
	}
}